{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "c626bbe8",
   "metadata": {},
   "source": [
    "## 实验二  神经网络\n",
    "### 第1.2题  累积BP算法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "5e903c80",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.ndarray'>\n"
     ]
    }
   ],
   "source": [
    "#  Wine, 数据预处理\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.preprocessing import LabelBinarizer, StandardScaler\n",
    "from sklearn.metrics import confusion_matrix, classification_report\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "#读数据\n",
    "wine = np.genfromtxt(\"wine_data-2.csv\", delimiter=\",\",skip_header=1)\n",
    "print(type(wine)) # numpy.ndarray\n",
    "X = wine[:,0:13] \n",
    "y = wine[:,13]\n",
    "# print(type(X))\n",
    "# print(type(y))\n",
    "\n",
    "x_train, x_test, y_train, y_test = train_test_split(X, y)   # 默认取出97个样本作为测试集，33个作为测试集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b6ce3519",
   "metadata": {},
   "outputs": [],
   "source": [
    "label_train = LabelBinarizer().fit_transform(y_train)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "af4d8bdf",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义激活函数及其导数\n",
    "def sigmoid(x):\n",
    "    return 1 / (1 + np.exp(-x))\n",
    "\n",
    "#激活函数的导数\n",
    "def d_sigmoid(x):\n",
    "    return x * (1 - x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "83e65de1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "n_samples= 97\n"
     ]
    },
    {
     "ename": "NameError",
     "evalue": "name 'sigmoid' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[3], line 85\u001b[0m\n\u001b[1;32m     82\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m w1,w2,b1,b2\n\u001b[1;32m     84\u001b[0m \u001b[38;5;66;03m#开始训练神经网络\u001b[39;00m\n\u001b[0;32m---> 85\u001b[0m w1,w2,b1,b2 \u001b[38;5;241m=\u001b[39m \u001b[43mtrain\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx_train\u001b[49m\u001b[43m,\u001b[49m\u001b[43mlabel_train\u001b[49m\u001b[43m,\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m   \u001b[38;5;66;03m#  1--输出神经元个数\u001b[39;00m\n",
      "Cell \u001b[0;32mIn[3], line 17\u001b[0m, in \u001b[0;36mtrain\u001b[0;34m(x, y, dim, eta, max_iter)\u001b[0m\n\u001b[1;32m     14\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m ite \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(max_iter):\n\u001b[1;32m     15\u001b[0m     \u001b[38;5;66;03m##前向传播   \u001b[39;00m\n\u001b[1;32m     16\u001b[0m     u1 \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mdot(x,w1)\u001b[38;5;241m+\u001b[39mb1   \u001b[38;5;66;03m#（97,13）x (13 , 50) --->（97,50）\u001b[39;00m\n\u001b[0;32m---> 17\u001b[0m     out1 \u001b[38;5;241m=\u001b[39m \u001b[43msigmoid\u001b[49m(u1)    \u001b[38;5;66;03m# 隐含层,（97,50）\u001b[39;00m\n\u001b[1;32m     18\u001b[0m     u2 \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mdot(out1,w2)\u001b[38;5;241m+\u001b[39mb2   \u001b[38;5;66;03m# （97,50）x (50, 1) --->（97,1）\u001b[39;00m\n\u001b[1;32m     19\u001b[0m     out2 \u001b[38;5;241m=\u001b[39m sigmoid(u2)    \u001b[38;5;66;03m#激活层，（97,1）\u001b[39;00m\n",
      "\u001b[0;31mNameError\u001b[0m: name 'sigmoid' is not defined"
     ]
    }
   ],
   "source": [
    "# 训练神经网络的函数\n",
    "def train(x,y,dim=1,eta=0.05,max_iter=1000):  # dim -- 输出单元数\n",
    "    n_samples = x.shape[0]  #  训练样本数，\n",
    "    print(\"n_samples=\",n_samples)\n",
    "    hiden_dim=50\n",
    "    #定义、初始化神经元的权重\n",
    "    w1 = np.zeros((x.shape[1],hiden_dim))  #  （13，50）  <--- 矩阵维数\n",
    "    b1 = np.zeros((1,hiden_dim))  # （1，50）\n",
    "    w2 = np.zeros((hiden_dim,1))  #  （50，1）\n",
    "    b2 = np.zeros((dim,1))  #  （1，1）  \n",
    "    \n",
    "    losslist = []    #损失列表\n",
    "    \n",
    "    for ite in range(max_iter):\n",
    "        ##前向传播   \n",
    "        u1 = np.dot(x,w1)+b1   #（97,13）x (13 , 50) --->（97,50）\n",
    "        out1 = sigmoid(u1)    # 隐含层,（97,50）\n",
    "        u2 = np.dot(out1,w2)+b2   # （97,50）x (50, 1) --->（97,1）\n",
    "        out2 = sigmoid(u2)    #激活层，（97,1）\n",
    "        \n",
    "        loss = np.mean(np.square(y - out2))/2    #均方误差，（97,1）\n",
    "        losslist.append(loss)\n",
    "#         print('iter:%d  loss:%.4f'%(ite,loss))\n",
    "\n",
    "        ##反向传播\n",
    "        ##累计BP\n",
    "        d_out2 = -(y - out2)   # （97,1）\n",
    "        d_u2 = d_out2*d_sigmoid(out2) # （97,1） 矩阵点乘\n",
    "        d_w2 = np.dot(np.transpose(out1),d_u2)  # np.transpose()--矩阵转置,（50,97）x (97, 1) --->（50,1）\n",
    "        d_b2 = d_u2  # (97,1)        \n",
    "        \n",
    "        d_out1 = np.dot(d_u2,np.transpose(w2)) # （97,1）x (1,50) --->（97,50）\n",
    "        \n",
    "        d_u1 = d_out1*d_sigmoid(out1)  # （97，50）点乘 (97, 50) --->（97，50）\n",
    "        \n",
    "        d_w1 = np.dot(np.transpose(x),d_u1) #  （13,97）x (97, 50) --->（13,50）\n",
    "        \n",
    "        d_b1 = d_u1  #（97，50）\n",
    "        \n",
    "        ##更新权重\n",
    "        w1 = w1 - eta*d_w1\n",
    "        w2 = w2 - eta*d_w2\n",
    "        b1 = b1 - eta*d_b1\n",
    "        b2 = b2 - eta*d_b2\n",
    "        test_label_list1 = []    #损失列表\n",
    "        for m in range(x_test.shape[0]):\n",
    "            xi,yi = x_test[m,:],label_test[m,:]\n",
    "            xi,yi = xi.reshape(1,xi.shape[0]),yi.reshape(1,yi.shape[0])\n",
    "            #前向传播   \n",
    "            u1 = np.dot(xi,w1)+b1\n",
    "            out1 = sigmoid(u1)    # 隐含层的输出  1 X 50\n",
    "            u2 = np.dot(out1,w2)+b2\n",
    "            out2 = sigmoid(u2)    #激活层    \n",
    "            if out2>=0.5:\n",
    "                test_label_list1.append(1)\n",
    "            else: \n",
    "                test_label_list1.append(0)\n",
    "        re1=0  # 记录测试正确的样本数\n",
    "            # 计算测试精度\n",
    "        for i in range(len(y_test)):\n",
    "            if test_label_list1[i]==y_test[i]:\n",
    "                re1=re1+1\n",
    "            else:\n",
    "                pass\n",
    "        acc = re1 / len(y_test) # 准确率等于正确分类的样本数除以总样本数\n",
    "        acc_list.append(acc) # 将准确率添加到列表中\n",
    "    \n",
    "    ##Loss可视化，损失函数曲线\n",
    "    plt.figure()\n",
    "    plt.plot([i+1 for i in range(max_iter)],losslist)\n",
    "    plt.legend(['accumlated BP'])\n",
    "    plt.xlabel('iteration')\n",
    "    plt.ylabel('loss')\n",
    "    plt.show()\n",
    "    plt.figure()\n",
    "    plt.plot([i + 1 for i in range(max_iter)], mse_list, label='MSE') # 绘制均方误差曲线，横轴为训练轮数，纵轴为均方误差，标签为'MSE'\n",
    "    plt.plot([i + 1 for i in range(max_iter)], acc_list, label='ACC') # 绘制准确率曲线，横轴为训练轮数，纵轴为准确率，标签为'ACC'\n",
    "    plt.legend() # 显示图例\n",
    "    plt.xlabel('iteration') # 设置横轴标签为'iteration'\n",
    "    plt.ylabel('metric') # 设置纵轴标签为'metric'\n",
    "    plt.show() # 显示图像\n",
    "    return w1,w2,b1,b2\n",
    "    \n",
    "#开始训练神经网络\n",
    "w1,w2,b1,b2 = train(x_train,label_train,1)   #  1--输出神经元个数"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:pytorch]",
   "language": "python",
   "name": "conda-env-pytorch-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
